#pragma once
#ifndef __WEBPAGEQUERY_H__
#define __WEBPAGEQUERY_H__
#include "WebPage.h"
#include "SplitTool.h"
#include "Mylogger.h"
#include "Configuration.h"
using std::unordered_map;
using std::map;
using std::set;
using std::pair;

struct Similarity{
    int docid;
    double cosValue;

    //对Similarity的<运算符进行重载，便于比较两个结果的热度
    friend bool operator<(const Similarity& lhs,const Similarity& rhs);
};

class WebPageQuery
{
public:
    WebPageQuery(SplitTool* tool,
                 Configuration* conf,
                 const string& cleanPageName = "../data/cleanedPage.dat",
                 const string& offsetLibPathname = "../data/noDupIndex.dat",
                 const string& invertIndexName = "../data/invertIndex.dat")
    :_cuttor(tool)
    ,_conf(conf)
    ,_cleanedPageName(cleanPageName)
    ,_offsetLibPathname(offsetLibPathname)
    ,_invertIndexName(invertIndexName)
    {
        //读取磁盘中的信息
        LogInfo("Reading configuration information");
        _conf->buildConf();
        buildStopSet();
        LogInfo("The data structure for the query is being built");
        readInfo();
    }
private:
    size_t nBytesCode(const char ch);
    void buildStopSet();    //获得停用词集合
    //读取出偏移库和倒排索引
    void readInfo();
    //对要查询的数据切分成单词,并计算出基准向量,map中的string为单词,double为权值
    void cutQuery(const string& query,vector<string>& words,map<string,double>& vec);
    //获得包含所有关键字的交集
    void getIntersection(const vector<string>& words,set<int>& docids);
    //计算出每个docid对应的向量
    void getAllVec(const vector<string>& words,const set<int>& docids,map<int,map<string,double>>& allvec);
    //计算出docid及其与要查询数据的余弦相似度
    void getSimilarity(const map<int,map<string,double>>allvec,const map<string,double>& vec,vector<Similarity>& similarity);
    //统计出余弦相似度最高的十片文档
    void getTopSimilarity(const vector<Similarity>& similarity,vector<int>& docids);
    //找出要返回的文章,并将其组织为Json格式
    void getResult(const vector<int>& docids,string& result);
    //从偏移库中读出一篇文章
    void getWebPage(int docid,string & paper);
    //解析从偏移库中读出的文章
    void parsePaper(string paper,WebPage& webPage);
    
public:
    //将结果以json格式的字符串返回
    void doQuery(const string& query,string& result);
private:
    SplitTool* _cuttor;
    Configuration* _conf;
    string _cleanedPageName;
    string _offsetLibPathname;
    string _invertIndexName;

    WebPage _webPage; //存放单个文章
    set<string> _stopWords; //停用词的集合
    //去重后的文档偏移库,int为docid,第一个int为起始位置,第二个int为文档长度
    unordered_map<int,pair<int,int>> _offsetLib;
    //倒排索引,string表示单词/词语,int为docid,double为权重
    unordered_map<string,set<pair<int,double>>> _invertIndex;
};

#endif
